using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Xml;
using System.Diagnostics;

namespace LonCanvas
{
   
    public class StationMapUtils
    {
        static StationMapUtils()
        {
            GridHeight = 10;
            GridWidth = 10;
        }
        public static PointF RightPoint(ICanvas canvas, RectangleF unitrect)
        {
            PointF leftpoint = unitrect.Location;
            float x = leftpoint.X + unitrect.Width;
            float y = leftpoint.Y + unitrect.Height;
            return new PointF(x, y);
        }
        public static RectangleF ToScreen(ICanvas canvas, RectangleF unitrect)
        {
            RectangleF r = new RectangleF();
            r.Location = canvas.ToScreen(new UnitPoint(unitrect.Location));
            r.Width = (float)Math.Round(canvas.ToScreen(unitrect.Width));
            r.Height = (float)Math.Round(canvas.ToScreen(unitrect.Height));
            return r;
        }
        public static RectangleF ToUnit(ICanvas canvas, Rectangle screenrect)
        {
            UnitPoint point = canvas.ToUnit(screenrect.Location);
            SizeF size = new SizeF((float)canvas.ToUnit(screenrect.Width), (float)canvas.ToUnit(screenrect.Height));
            RectangleF unitrect = new RectangleF(point.Point, size);
            return unitrect;
        }
        public static RectangleF ToScreenNormalized(ICanvas canvas, RectangleF unitrect)
        {
            RectangleF r = ToScreen(canvas, unitrect);
            r.Y = r.Y - r.Height;
            return r;
        }
        public static RectangleF ToUnitNormalized(ICanvas canvas, Rectangle screenrect)
        {
            UnitPoint point = canvas.ToUnit(screenrect.Location);
            SizeF size = new SizeF((float)canvas.ToUnit(screenrect.Width), (float)canvas.ToUnit(screenrect.Height));
            RectangleF unitrect = new RectangleF(point.Point, size);
            unitrect.Y = unitrect.Y - unitrect.Height; // 
            return unitrect;
        }
        public static Rectangle ConvertRect(RectangleF r)
        {
            return new Rectangle((int)r.Left, (int)r.Top, (int)r.Width, (int)r.Height);
        }

        public static RectangleF GetRect(Point p1, int width, int height)
        {
            double x = p1.X * GridWidth;
            double y = p1.Y * GridHeight;
            double w = width * GridWidth;
            double h = height * GridHeight;
            RectangleF rect = StationMapUtils.GetRect(x, y, w, h);

            return rect;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="width"></param>
        /// <returns></returns>
        public static RectangleF GetRect(Point p1, Point p2, double width)
        {
            double x = Math.Min(p1.X * GridWidth, p2.X * GridWidth);
            double y = Math.Min(p1.Y * GridHeight, p2.Y * GridHeight);
            double w = Math.Abs(p1.X * GridWidth - p2.X * GridWidth);
            double h = Math.Abs(p1.Y * GridHeight - p2.Y * GridHeight);
            RectangleF rect = StationMapUtils.GetRect(x, y, w, h);
            rect.Inflate((float)width, (float)width);
            return rect;
        }
        public static RectangleF GetRect(double x, double y, double w, double h)
        {
            return new RectangleF((float)x, (float)y, (float)w, (float)h);
        }

        public static UnitPoint ConvertPoint(Point p)
        {
            return new UnitPoint((int)p.X * GridWidth, (int)p.Y * GridHeight);
        }
        public static Point ConvertToGridPoint(UnitPoint p)
        {
            return new Point((int)Math.Round(p.X / GridWidth), (int)Math.Round(p.Y / GridHeight));
        }

        public static int GridWidth { get; set; }
        public static int GridHeight { get; set; }
        public static Point CovertToGridPoint(Point p)
        {

            return new Point((int)Math.Round(p.X * 1.0 / GridWidth), (int)Math.Round(p.Y * 1.0 / GridHeight));

        }

    }
    public class ScreenUtils
    {
        public static PointF RightPoint(ICanvas canvas, RectangleF unitrect)
        {
            PointF leftpoint = unitrect.Location;
            float x = leftpoint.X + unitrect.Width;
            float y = leftpoint.Y + unitrect.Height;
            return new PointF(x, y);
        }
        public static RectangleF ToScreen(ICanvas canvas, RectangleF unitrect)
        {
            RectangleF r = new RectangleF();
            r.Location = canvas.ToScreen(new UnitPoint(unitrect.Location));
            r.Width = (float)Math.Round(canvas.ToScreen(unitrect.Width));
            r.Height = (float)Math.Round(canvas.ToScreen(unitrect.Height));
            return r;
        }
        public static RectangleF ToUnit(ICanvas canvas, Rectangle screenrect)
        {
            UnitPoint point = canvas.ToUnit(screenrect.Location);
            SizeF size = new SizeF((float)canvas.ToUnit(screenrect.Width), (float)canvas.ToUnit(screenrect.Height));
            RectangleF unitrect = new RectangleF(point.Point, size);
            return unitrect;
        }
        public static RectangleF ToScreenNormalized(ICanvas canvas, RectangleF unitrect)
        {
            RectangleF r = ToScreen(canvas, unitrect);
            //r.Y = r.Y - r.Height;
            r.Y = r.Y;
            return r;
        }
        public static RectangleF ToUnitNormalized(ICanvas canvas, Rectangle screenrect)
        {
            UnitPoint point = canvas.ToUnit(screenrect.Location);
            SizeF size = new SizeF((float)canvas.ToUnit(screenrect.Width), (float)canvas.ToUnit(screenrect.Height));
            RectangleF unitrect = new RectangleF(point.Point, size);
            unitrect.Y = unitrect.Y;
            // unitrect.Y = unitrect.Y - unitrect.Height; // 
            return unitrect;
        }
        public static Rectangle ConvertRect(RectangleF r)
        {
            return new Rectangle((int)r.Left, (int)r.Top, (int)r.Width, (int)r.Height);
        }
        public static RectangleF GetRect(UnitPoint p1, UnitPoint p2, double width)
        {
            double x = Math.Min(p1.X, p2.X);
            double y = Math.Min(p1.Y, p2.Y);
            double w = Math.Abs(p1.X - p2.X);
            double h = Math.Abs(p1.Y - p2.Y);
            RectangleF rect = ScreenUtils.GetRect(x, y, w, h);
            rect.Inflate((float)width, (float)width);
            return rect;
        }
        public static RectangleF GetRect(double x, double y, double w, double h)
        {
            return new RectangleF((float)x, (float)y, (float)w, (float)h);
        }
        public static Point ConvertPoint(PointF p)
        {
            return new Point((int)p.X, (int)p.Y);
        }
    }
    public class HitUtil
    {
        public static bool PointInPoint(UnitPoint p, UnitPoint tp, float tpThresHold)
        {
            if (p.IsEmpty || tp.IsEmpty)
                return false;
            if ((p.X < tp.X - tpThresHold) || (p.X > tp.X + tpThresHold))
                return false;
            if ((p.Y < tp.Y - tpThresHold) || (p.Y > tp.Y + tpThresHold))
                return false;
            return true;
        }

        public static double Distance(UnitPoint p1, UnitPoint p2)
        {
            return Distance(p1, p2, true);
        }
        public static double Distance(UnitPoint p1, UnitPoint p2, bool abs)
        {
            double dx = p1.X - p2.X;
            double dy = p1.Y - p2.Y;
            if (abs)
            {
                dx = Math.Abs(dx);
                dy = Math.Abs(dy);
            }
            if (dx == 0)
                return dy;
            if (dy == 0)
                return dx;
            return Math.Sqrt(Math.Pow(dx, 2) + Math.Pow(dy, 2));
        }
        public static double RadiansToDegrees(double radians)
        {
            return radians * (180 / Math.PI);
        }
        public static double DegressToRadians(double degrees)
        {
            return degrees * (Math.PI / 180);
        }

        public static RectangleF CircleBoundingRect(UnitPoint center, float radius)
        {
            RectangleF r = new RectangleF(center.Point, new SizeF(0, 0));
            r.Inflate(radius, radius);
            return r;
        }
        public static bool CircleHitPoint(UnitPoint center, float radius, UnitPoint hitpoint)
        {
            // check bounding rect, this is faster than creating a new rectangle and call r.Contains
            double leftPoint = center.X - radius;
            double rightPoint = center.X + radius;
            if (hitpoint.X < leftPoint || hitpoint.X > rightPoint)
                return false;

            double bottomPoint = center.Y - radius;
            double topPoint = center.Y + radius;
            if (hitpoint.Y < bottomPoint || hitpoint.Y > topPoint)
                return false;

            return true;
        }
        public static bool CircleIntersectWithLine(UnitPoint center, float radius, UnitPoint lp1, UnitPoint lp2)
        {
            // check if both points are inside the circle, in that case the line does not intersect the circle
            if ((Distance(center, lp1) < radius && Distance(center, lp2) < radius))
                return false;

            // find the nearest point from the line to center, if that point is smaller than radius, 
            // then the line does intersect the circle
            UnitPoint np = NearestPointOnLine(lp1, lp2, center);
            double dist = Distance(center, np);
            if (dist <= radius)
                return true;
            return false;
        }
        public static bool IsPointInCircle(UnitPoint center, float radius, UnitPoint testpoint, float halflinewidth)
        {
            double dist = Distance(center, testpoint);
            if ((dist >= radius - halflinewidth) && (dist <= radius + halflinewidth))
                return true;
            return false;
        }
        public static UnitPoint NearestPointOnCircle(UnitPoint center, float radius, UnitPoint testpoint, double roundToAngleD)
        {
            double A = LineAngleR(center, testpoint, DegressToRadians(roundToAngleD));
            double dx = Math.Cos(A) * radius;
            double dy = Math.Sin(A) * radius;
            double dist = Math.Sqrt(Math.Pow(dx, 2) + Math.Pow(dy, 2));
            return new UnitPoint((float)(center.X + dx), (float)(center.Y + dy));
        }
        public static UnitPoint TangentPointOnCircle(UnitPoint center, float radius, UnitPoint testpoint, bool reverse)
        {
            // c = center, p = testpoint, r = radius
            // tangent point is formed by a rightangled triangle where 'cp' is the hyportenuse 
            // and the 2 legs are 'r' and cr.
            double h = Math.Sqrt(Math.Pow(center.X - testpoint.X, 2) + Math.Pow(center.Y - testpoint.Y, 2));
            double r = radius;
            if (Math.Abs(h) < r)	// point located inside the circle, no tangent point
                return UnitPoint.Empty;

            // A1 is the angle from center to testpoint
            // A2 is the angle from center to testpoint when radius is used as height for rightangled triangle
            // A3 is the remaining angle between 'cp' line (h) and the short leg of the tangent triangle
            double A1 = LineAngleR(center, testpoint, 0);
            double A2 = Math.Asin(r / h);
            double A3 = Math.Acos(r / h);

            // The angle for the tangent point is 90 + diff between A1 and A2
            double A = Math.PI / 2 + (A1 - A2);
            // if reverse, mirror around A1
            if (reverse)
                A = A1 - A3;
            return LineEndpoint(center, A, radius);
        }
        public static UnitPoint PointOncircle(UnitPoint center, double radius, double angleR)
        {
            double y = center.Y + Math.Sin(angleR) * radius;
            double x = center.X + Math.Cos(angleR) * radius;
            return new UnitPoint((float)x, (float)y);
        }
        public static UnitPoint LineEndpoint(UnitPoint lp1, double angleR, double length)
        {
            double x = Math.Cos(angleR) * length;
            double y = Math.Sin(angleR) * length;
            return new UnitPoint(lp1.X + (float)x, lp1.Y + (float)y);
        }
        public static RectangleF LineBoundingRect(UnitPoint linepoint1, UnitPoint linepoint2, float halflinewidth)
        {
            double x = Math.Min(linepoint1.X, linepoint2.X);
            double y = Math.Min(linepoint1.Y, linepoint2.Y);
            double w = Math.Abs(linepoint1.X - linepoint2.X);
            double h = Math.Abs(linepoint1.Y - linepoint2.Y);
            RectangleF boundingrect = ScreenUtils.GetRect(x, y, w, h);
            boundingrect.Inflate(halflinewidth, halflinewidth);
            return boundingrect;
        }

        private static bool LinesIntersect(UnitPoint lp1, UnitPoint lp2, UnitPoint lp3, UnitPoint lp4, ref double x, ref double y,
            bool returnpoint,
            bool extendA,
            bool extendB)
        {
            // http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
            // line a is given by P1 and P2, point of intersect for line a (Pa) and b (Pb)
            // Pa = P1 + ua ( P2 - P1 )
            // Pb = P3 + ub ( P4 - P3 )

            // ua(x) = ub(x) and ua(y) = ub (y)
            // x1 + ua (x2 - x1) = x3 + ub (x4 - x3)
            // y1 + ua (y2 - y1) = y3 + ub (y4 - y3)

            // ua = ((x4-x3)(y1-y3) - (y4-y3)(x1-x3)) / ((x4-x3)(x2-x1) - (x4-x3)(y2-y1))
            // ub = ((x2-x1)(y1-y3) - (y2-y1)(x1-x3)) / ((y4-y3)(x2-x1) - (x4-x3)(y2-y1))

            // intersect point x = x1 + ua (x2 - x1)
            // intersect point y = y1 + ua (y2 - y1) 
            double x1 = lp1.X;
            double x2 = lp2.X;
            double x3 = lp3.X;
            double x4 = lp4.X;
            double y1 = lp1.Y;
            double y2 = lp2.Y;
            double y3 = lp3.Y;
            double y4 = lp4.Y;

            double denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));
            if (denominator == 0) // lines are parallel
                return false;
            double numerator_ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3));
            double numerator_ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3));
            double ua = numerator_ua / denominator;
            double ub = numerator_ub / denominator;
            // if a line is not extended then ua (or ub) must be between 0 and 1
            if (extendA == false)
            {
                if (ua < 0 || ua > 1)
                    return false;
            }
            if (extendB == false)
            {
                if (ub < 0 || ub > 1)
                    return false;
            }
            if (extendA || extendB) // no need to chck range of ua and ub if check is one on lines 
            {
                x = x1 + ua * (x2 - x1);
                y = y1 + ua * (y2 - y1);
                return true;
            }
            if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
            {
                if (returnpoint)
                {
                    x = x1 + ua * (x2 - x1);
                    y = y1 + ua * (y2 - y1);
                }
                return true;
            }
            return false;
        }
        public static bool LinesIntersect(UnitPoint lp1, UnitPoint lp2, UnitPoint lp3, UnitPoint lp4)
        {
            double x = 0;
            double y = 0;
            return LinesIntersect(lp1, lp2, lp3, lp4, ref x, ref y, false, false, false);
        }
        public static UnitPoint LinesIntersectPoint(UnitPoint lp1, UnitPoint lp2, UnitPoint lp3, UnitPoint lp4)
        {
            double x = 0;
            double y = 0;
            if (LinesIntersect(lp1, lp2, lp3, lp4, ref x, ref y, true, false, false))
                return new UnitPoint(x, y);
            return UnitPoint.Empty;
        }
        public static UnitPoint FindApparentIntersectPoint(UnitPoint lp1, UnitPoint lp2, UnitPoint lp3, UnitPoint lp4)
        {
            double x = 0;
            double y = 0;
            if (LinesIntersect(lp1, lp2, lp3, lp4, ref x, ref y, true, true, true))
                return new UnitPoint(x, y);
            return UnitPoint.Empty;
        }
        public static UnitPoint FindApparentIntersectPoint(UnitPoint lp1, UnitPoint lp2, UnitPoint lp3, UnitPoint lp4, bool extendA, bool extendB)
        {
            double x = 0;
            double y = 0;
            if (LinesIntersect(lp1, lp2, lp3, lp4, ref x, ref y, true, extendA, extendB))
                return new UnitPoint(x, y);
            return UnitPoint.Empty;
        }
        public static bool LineIntersectWithRect(UnitPoint lp1, UnitPoint lp2, RectangleF r)
        {
            if (r.Contains(lp1.Point))
                return true;
            if (r.Contains(lp2.Point))
                return true;

            // the rectangle bottom is top in world units and top is bottom!, confused?
            // check left
            UnitPoint p3 = new UnitPoint(r.Left, r.Top);
            UnitPoint p4 = new UnitPoint(r.Left, r.Bottom);
            if (LinesIntersect(lp1, lp2, p3, p4))
                return true;
            // check bottom
            p4.Y = r.Top;
            p4.X = r.Right;
            if (LinesIntersect(lp1, lp2, p3, p4))
                return true;
            // check right
            p3.X = r.Right;
            p3.Y = r.Top;
            p4.X = r.Right;
            p4.Y = r.Bottom;
            if (LinesIntersect(lp1, lp2, p3, p4))
                return true;
            return false;
        }
        public static UnitPoint LineMidpoint(UnitPoint lp1, UnitPoint lp2)
        {
            UnitPoint mid = new UnitPoint();
            mid.X = (lp1.X + lp2.X) / 2;
            mid.Y = (lp1.Y + lp2.Y) / 2;
            return mid;
        }
        public static double LineAngleR(UnitPoint lp1, UnitPoint lp2, double roundToAngleR)
        {
            if (lp1.X == lp2.X)
            {
                if (lp1.Y > lp2.Y)
                    return Math.PI * 6 / 4;
                if (lp1.Y < lp2.Y)
                    return Math.PI / 2;
                return 0;
            }
            // first find angle A
            double adjacent = lp2.X - lp1.X;
            double opposite = lp2.Y - lp1.Y;
            // find angle A
            double A = Math.Atan(opposite / adjacent);
            if (adjacent < 0)			// 2nd and 3rd quadrant
                A += Math.PI;			// + 180
            if (adjacent > 0 && opposite < 0) // 4th quadrant
                A += Math.PI * 2;		// +360
            if (roundToAngleR != 0)
            {
                double roundUnit = Math.Round(A / roundToAngleR);
                A = roundToAngleR * roundUnit;
            }
            return A;
        }
        public static UnitPoint OrthoPointD(UnitPoint lp1, UnitPoint lp2, double roundToAngleR)
        {
            return OrthoPointR(lp1, lp2, DegressToRadians(roundToAngleR));
        }
        public static UnitPoint OrthoPointR(UnitPoint lp1, UnitPoint lp2, double roundToAngleR)
        {
            return NearestPointOnLine(lp1, lp2, lp2, roundToAngleR);
        }
        public static UnitPoint NearestPointOnLine(UnitPoint lp1, UnitPoint lp2, UnitPoint tp)
        {
            return NearestPointOnLine(lp1, lp2, tp, false);
        }
        public static UnitPoint NearestPointOnLine(UnitPoint lp1, UnitPoint lp2, UnitPoint tp, bool beyondSegment)
        {
            if (lp1.X == lp2.X)
            {
                // if both points are to below, then choose the points closest to tp.y
                if (beyondSegment == false && lp1.Y < tp.Y && lp2.Y < tp.Y)
                    return new UnitPoint(lp1.X, Math.Max(lp1.Y, lp2.Y));
                // if both points are above, then choose the points closest to tp.y
                if (beyondSegment == false && lp1.Y > tp.Y && lp2.Y > tp.Y)
                    return new UnitPoint(lp1.X, Math.Min(lp1.Y, lp2.Y));
                // else the line is on both sides and pick tp.x as y point
                return new UnitPoint(lp1.X, tp.Y);
            }
            if (lp1.Y == lp2.Y)
            {
                // if both points are to the right, then choose the points closest to tp.x
                if (beyondSegment == false && lp1.X < tp.X && lp2.X < tp.X)
                    return new UnitPoint(Math.Max(lp1.X, lp2.X), lp1.Y);
                // if both points are to the left, then choose the points closest to tp.x
                if (beyondSegment == false && lp1.X > tp.X && lp2.X > tp.X)
                    return new UnitPoint(Math.Min(lp1.X, lp2.X), lp1.Y);
                // else the line is on both sides and pick tp.x as x point
                return new UnitPoint(tp.X, lp1.Y);
            }
            return NearestPointOnLine(lp1, lp2, tp, 0);
        }
        private static UnitPoint NearestPointOnLine(UnitPoint lp1, UnitPoint lp2, UnitPoint testpoint, double roundToAngleR)
        {
            if (lp1.X == testpoint.X)
            {
                UnitPoint tmp = lp1;
                lp1 = lp2;
                lp2 = tmp;
            }
            double A1 = LineAngleR(lp1, testpoint, 0);
            double A2 = LineAngleR(lp1, lp2, roundToAngleR);
            double A = A1 - A2;
            double h1 = (lp1.X - testpoint.X) / Math.Cos(A1);
            double h2 = Math.Cos(A) * h1;
            double x = Math.Cos(A2) * h2;
            double y = Math.Sin(A2) * h2;
            x = lp1.X - x;
            y = lp1.Y - y;
            return new UnitPoint((float)x, (float)y);
        }
        public static double LineSlope(UnitPoint p1, UnitPoint p2)
        {
            return (p2.Y - p1.Y) / (p2.X - p1.X);
        }
        public static UnitPoint CenterPointFrom3Points(UnitPoint p1, UnitPoint p2, UnitPoint p3)
        {
            // http://local.wasp.uwa.edu.au/~pbourke/geometry/circlefrom3/
            // 3 points forms 2 lines a and b, slope of a is ma, b is mb
            // ma = (y2-y1) / (x2-x1)
            // mb = (y3-y2) / (x3-x2)
            double ma = (p2.Y - p1.Y) / (p2.X - p1.X);
            double mb = (p3.Y - p2.Y) / (p3.X - p2.X);

            // this is just a hacky work around for when p1-p2 are either horizontal or vertical.
            // A real solution should be found, but for now this will work
            if (double.IsInfinity(ma))
                ma = 1000000000000;
            if (double.IsInfinity(mb))
                mb = 1000000000000;
            if (ma == 0)
                ma = 0.000000000001;
            if (mb == 0f)
                mb = 0.000000000001;

            // centerpoint x = mamb(y1-y3) + mb(x1+x2) - ma(x2+x3) / 2(mb-ma)
            double center_x = (ma * mb * (p1.Y - p3.Y) + mb * (p1.X + p2.X) - ma * (p2.X + p3.X)) / (2 * (mb - ma));
            double center_y = (-1 * (center_x - (p1.X + p2.X) / 2) / ma) + ((p1.Y + p2.Y) / 2);

            //m_Center.m_y = -1*(m_Center.x() - (pt1->x()+pt2->x())/2)/aSlope +  (pt1->y()+pt2->y())/2;
            return new UnitPoint((float)center_x, (float)center_y);
        }
    }
    public class SelectionRectangle
    {
        PointF m_point1;
        PointF m_point2;
        public SelectionRectangle(PointF mousedownpoint)
        {
            m_point1 = mousedownpoint;
            m_point2 = PointF.Empty;
        }
        public void Reset()
        {
            m_point2 = PointF.Empty;
        }
    
        public Rectangle ScreenRect()
        {
            float x = Math.Min(m_point1.X, m_point2.X);
            float y = Math.Min(m_point1.Y, m_point2.Y);
            float w = Math.Abs(m_point1.X - m_point2.X);
            float h = Math.Abs(m_point1.Y - m_point2.Y);
            if (m_point2 == PointF.Empty)
                return Rectangle.Empty;
            if (w < 4 || h < 4) // if no selection was made return empty rectangle (giving a 4 pixel threshold)
                return Rectangle.Empty;
            return new Rectangle((int)x, (int)y, (int)w, (int)h);
        }
        public RectangleF Selection(ICanvas canvas)
        {
            Rectangle screenRect = ScreenRect();
            if (screenRect.IsEmpty)
                return RectangleF.Empty;
            return ScreenUtils.ToUnitNormalized(canvas, screenRect);
        }
        public bool AnyPoint()
        {
            return (m_point1.X > m_point2.X);
        }
        private Color GetColor()
        {
            if (AnyPoint())
                return Color.Blue;
            return Color.Green;
        }
    }
//    public class MoveHelper
//    {
//        List<IDrawObject> m_originals = new List<IDrawObject>();
//        List<IDrawObject> m_copies = new List<IDrawObject>();
//        UnitPoint m_originPoint = UnitPoint.Empty;
//        UnitPoint m_lastPoint = UnitPoint.Empty;
//        CanvasCtrl m_canvas;
//        public UnitPoint OriginPoint
//        {
//            get { return m_originPoint; }
//        }
//        public UnitPoint LastPoint
//        {
//            get { return m_lastPoint; }
//        }
//        public IEnumerable<IDrawObject> Copies
//        {
//            get { return m_copies; }
//        }
//        public MoveHelper(CanvasCtrl canvas)
//        {
//            m_canvas = canvas;
//        }
//        public bool IsEmpty
//        {
//            get { return m_copies.Count == 0; }
//        }
//        public bool HandleMouseMoveForMove(UnitPoint mouseunitpoint)
//        {
//            if (m_originals.Count == 0)
//                return false;
//            double x = mouseunitpoint.X - m_lastPoint.X;
//            double y = mouseunitpoint.Y - m_lastPoint.Y;
//            UnitPoint offset = new UnitPoint(x, y);
//            m_lastPoint = mouseunitpoint;
//            Trace.WriteLine(x.ToString() + "," + y.ToString());

//            foreach (IDrawObject obj in m_copies)
//            {
//                //Trace.WriteLine(((OneLineTrack)obj).DrawObjects[0]);
//                obj.Move(offset);
//                //Trace.WriteLine(((OneLineTrack)obj).DrawObjects[0]);
//            }
//            m_canvas.DoInvalidate(true);
//            return true;
//        }
//        public void HandleCancelMove()
//        {
//            foreach (IDrawObject obj in m_originals)
//                m_canvas.Model.AddSelectedObject(obj);
//            m_originals.Clear();
//            m_copies.Clear();
//            m_canvas.DoInvalidate(true);
//        }
//        public void HandleMouseDownForMove(UnitPoint mouseunitpoint, ISnapPoint snappoint)
//        {
//            UnitPoint p = mouseunitpoint;
//            if (snappoint != null)
//                p = snappoint.SnapPoint;

//            if (m_originals.Count == 0) // first step of move
//            {
//                foreach (IDrawObject obj in m_canvas.Model.SelectedObjects)
//                {
//                    m_originals.Add(obj);
//                    m_copies.Add(obj.Clone());
//                }
//                m_canvas.Model.ClearSelectedObjects();
//                m_originPoint = p;
//                m_lastPoint = p;
//            }
//            else // move complete
//            {
//                double x = p.X - m_originPoint.X;
//                double y = p.Y - m_originPoint.Y;
//                UnitPoint offset = new UnitPoint(x, y);

//                // do copy
//                if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
//                {
//                    m_canvas.Model.CopyObjects(offset, m_originals);
//                }
//                else
//                {
//                    // do move
//     //               m_canvas.Model.MoveObjects(offset, m_originals);
//                    foreach (IDrawObject obj in m_originals)
//                        m_canvas.Model.AddSelectedObject(obj);
//                }
//                m_originals.Clear();
//                m_copies.Clear();

//            }
//            m_canvas.DoInvalidate(true);
//        }

//        public void StartMove(UnitPoint mouseunitpoint, ISnapPoint snappoint)
//        {
//            UnitPoint p = mouseunitpoint;
//            if (snappoint != null)
//                p = snappoint.SnapPoint;

//            if (m_originals.Count == 0)
//            {
//                foreach (IDrawObject obj in m_canvas.Model.SelectedObjects)
//                {
//                    m_originals.Add(obj);
//                    m_copies.Add(obj.Clone());
//                }
//                m_canvas.Model.ClearSelectedObjects();
//                m_originPoint = p;
//                m_lastPoint = p;
//            }


//            return;

//        }


   

//        public void MoveStop(UnitPoint mouseunitpoint, ISnapPoint snappoint)
//        {
//            UnitPoint p = mouseunitpoint;
//            if (snappoint != null)
//                p = snappoint.SnapPoint;

//            if (m_originals.Count == 0) return;


//            double x =Math.Round(p.X - m_originPoint.X);
//            double y = Math.Round(p.Y - m_originPoint.Y);
            
//            UnitPoint offset = new UnitPoint(x, y);

//            // do copy
//            if ((Control.ModifierKeys & Keys.Control) == Keys.Control)
//            {
//                m_canvas.Model.CopyObjects(offset, m_originals);
//            }
//            else
//            {
//                // do move
//                m_canvas.Model.MoveObjects(offset, m_originals);

//                foreach (IDrawObject obj in m_originals)
//                {
//                    if (obj is StationControlBase)
//                    {
//                        ((StationControlBase)obj).RefreshDrawObjects();
//                    }
//                    m_canvas.Model.AddSelectedObject(obj);
//                }
//            }
//            m_originals.Clear();
//            m_copies.Clear();
//            m_canvas.DoInvalidate(true);

//        }
//        public void DrawObjects(ICanvas canvas, RectangleF r)
//        {
//            if (m_copies.Count == 0)
//                return;
//            canvas.Graphics.DrawLine(Pens.Wheat, canvas.ToScreen(OriginPoint), canvas.ToScreen(LastPoint));
//            foreach (IDrawObject obj in Copies)
//            {
// //               Trace.WriteLine("Draw Copy");
////                Trace.WriteLine(((OneLineTrack)obj).DrawObjects[0]);
//                obj.Draw(canvas, r);
//            }
//        }
//    }
//    public class NodeMoveHelper
//    {
//        List<INodePoint> m_nodes = new List<INodePoint>();
//        UnitPoint m_originPoint = UnitPoint.Empty;
//        UnitPoint m_lastPoint = UnitPoint.Empty;
//        CanvasWrapper m_canvas;
//        public bool IsEmpty
//        {
//            get { return m_nodes.Count == 0; }
//        }
//        public NodeMoveHelper(CanvasWrapper canvas)
//        {
//            m_canvas = canvas;
//        }
//        public RectangleF HandleMouseMoveForNode(UnitPoint mouseunitpoint)
//        {
//            RectangleF r = RectangleF.Empty;
//            if (m_nodes.Count == 0)
//                return r;
//            r = new RectangleF(m_originPoint.Point, new Size(0, 0));
//            r = RectangleF.Union(r, new RectangleF(mouseunitpoint.Point, new SizeF(0, 0)));
//            if (m_lastPoint != UnitPoint.Empty)
//                r = RectangleF.Union(r, new RectangleF(m_lastPoint.Point, new SizeF(0, 0)));

//            m_lastPoint = mouseunitpoint;
//            foreach (INodePoint p in m_nodes)
//            {
//                if (r == RectangleF.Empty)
//                    r = p.GetClone().GetBoundingRect(m_canvas);
//                else
//                    r = RectangleF.Union(r, p.GetClone().GetBoundingRect(m_canvas));
//                p.SetPosition(mouseunitpoint);
//                //m_canvas.RepaintObject(p.GetClone());
//            }
//            return r;
//        }
//        public bool HandleMouseDown(UnitPoint mouseunitpoint, ref bool handled)
//        {
//            handled = false;
//            if (m_nodes.Count == 0) // no nodes selected yet
//            {
//                if (m_canvas.Model.SelectedCount > 0)
//                {
//                    foreach (IDrawObject obj in m_canvas.Model.SelectedObjects)
//                    {
//                        INodePoint p = obj.NodePoint(m_canvas, mouseunitpoint);
//                        if (p != null)
//                            m_nodes.Add(p);
//                    }
//                }
//                handled = m_nodes.Count > 0;
//                if (handled)
//                    m_originPoint = mouseunitpoint;
//                return handled;
//            }
//            // update selected nodes
//            m_canvas.Model.MoveNodes(mouseunitpoint, m_nodes);
//            m_nodes.Clear();
//            handled = true;
//            m_canvas.CanvasCtrl.DoInvalidate(true);
//            return handled;
//        }
//        public void HandleCancelMove()
//        {
//            foreach (INodePoint p in m_nodes)
//                p.Cancel();

//            m_nodes.Clear();
//        }
//        public void DrawOriginalObjects(ICanvas canvas, RectangleF r)
//        {
//            foreach (INodePoint node in m_nodes)
//                node.GetOriginal().Draw(canvas, r);
//        }
//        public void DrawObjects(ICanvas canvas, RectangleF r)
//        {
//            if (m_nodes.Count == 0)
//                return;
//            //canvas.Graphics.DrawLine(Pens.Wheat, canvas.ToScreen(m_originPoint), canvas.ToScreen(m_lastPoint));
//            foreach (INodePoint node in m_nodes)
//                node.GetClone().Draw(canvas, r);
//        }
//        public void OnKeyDown(ICanvas canvas, KeyEventArgs keyevent)
//        {
//            foreach (INodePoint nodepoint in m_nodes)
//            {
//                nodepoint.OnKeyDown(canvas, keyevent);
//                if (keyevent.Handled)
//                    return;

//                IDrawObject drawobject = nodepoint.GetClone();
//                if (drawobject == null)
//                    continue;
//                drawobject.OnKeyDown(canvas, keyevent);
//            }
//        }
//    }
    public class Utils
    {
        public static IDrawObject FindObjectTypeInList(IDrawObject caller, List<IDrawObject> list, Type type)
        {
            foreach (IDrawObject obj in list)
            {
                if (object.ReferenceEquals(caller, obj))
                    continue;
                if (obj.GetType() == type)
                    return obj;
            }
            return null;
        }
    }
}
